package com.canaan.business.controller.pc.bill;

import cn.hutool.core.lang.Pair;
import cn.hutool.json.JSONUtil;
import com.canaan.business.common.enums.agv.AgvEnum;
import com.canaan.business.common.enums.inOutStock.ErpBillTypeEnum;
import com.canaan.business.common.enums.inOutStock.InOrderStatusEnum;
import com.canaan.business.common.enums.inOutStock.OutOrderStatusEnum;
import com.canaan.business.common.enums.storehouse.StoreHouseLocationTypeEnum;
import com.canaan.business.common.enums.storehouse.StorehouseStockStatusEnum;
import com.canaan.business.domain.basic.WmsStorehouseLocation;
import com.canaan.business.domain.bill.BillDetailRecord;
import com.canaan.business.domain.bill.TrayDetail;
import com.canaan.business.domain.inOutStock.*;
import com.canaan.business.domain.storehouse.WmsStorehouseStock;
import com.canaan.business.domain.vo.*;
import com.canaan.business.service.agv.IAgvTaskDispatchService;
import com.canaan.business.service.basic.IWmsStorehouseLocationService;
import com.canaan.business.service.bill.ITrayDetailService;
import com.canaan.business.service.inOutStock.*;
import com.canaan.business.service.storehouse.IStorehouseStockStrategyService;
import com.canaan.business.service.storehouse.IWmsStorehouseStockService;
import com.canaan.common.encrypt.PushEdiService;
import com.canaan.business.domain.bill.AdjustOutBill;
import com.canaan.business.domain.bill.AdjustOutBillDetail;
import com.canaan.business.service.bill.IAdjustOutBillDetailService;
import com.canaan.business.service.bill.IAdjustOutBillService;
import com.canaan.common.annotation.Log;
import com.canaan.common.core.controller.BaseController;
import com.canaan.common.core.domain.AjaxResult;
import com.canaan.common.core.page.TableDataInfo;
import com.canaan.common.enums.BusinessType;
import com.canaan.common.exception.ServiceException;
import com.canaan.common.utils.DateUtils;
import com.canaan.common.utils.StringUtils;
import com.canaan.common.utils.TableNoUtil;
import com.canaan.common.utils.poi.ExcelUtil;
import com.canaan.system.service.ISysConfigService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 调拔出库单Controller
 *
 * @author ruoyi
 * @date 2023-02-01
 */
@Api(tags = "调拔出库单")
@RestController
@RequestMapping("/bill/adjustOut")
public class AdjustOutBillController extends BaseController {
    @Resource
    private IAdjustOutBillService adjustOutBillService;
    @Resource
    private IAdjustOutBillDetailService adjustOutBillDetailService;

    @Resource
    private ISysConfigService sysConfigService;

    /**
     * 查询调拔出库单列表
     */
    @ApiOperation(value = "查询调拔出库单列表")
    @GetMapping("/list")
    public TableDataInfo list(AdjustOutBill adjustOutBill) {
        startPage();
        List<AdjustOutBill> list = adjustOutBillService.selectAdjustOutBillListPageDatas(adjustOutBill);
        return getDataTable(list);
    }

    /**
     * 导出调拔出库单列表
     */
    @ApiOperation(value = "导出调拔出库单列表")
    @Log(title = "调拔出库单", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, AdjustOutBill adjustOutBill) {
        List<AdjustOutBillExportVo> list = adjustOutBillService.exportList(adjustOutBill);
        ExcelUtil<AdjustOutBillExportVo> util = new ExcelUtil<>(AdjustOutBillExportVo.class);
        util.exportExcel(response, list, "调拔出库单数据");
    }

    /**
     * 获取调拔出库单详细信息
     */
    @ApiOperation(value = "获取调拔出库单详细信息")
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") Long id) {
        return success(adjustOutBillService.selectAdjustOutBillById(id));
    }

    /**
     * 新增调拔出库单
     */
    @ApiOperation(value = "新增调拔出库单")
    @Log(title = "调拔出库单", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody AdjustOutBill adjustOutBill) {
        return toAjax(adjustOutBillService.insertAdjustOutBill(adjustOutBill));
    }

    /**
     * 修改调拔出库单
     */
    @ApiOperation(value = "修改调拔出库单")
    @Log(title = "调拔出库单", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody AdjustOutBill adjustOutBill) {
        return toAjax(adjustOutBillService.updateAdjustOutBill(adjustOutBill));
    }

    /**
     * 删除调拔出库单
     */
    @ApiOperation(value = "删除调拔出库单")
    @Log(title = "调拔出库单", businessType = BusinessType.DELETE)
	@DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable Long[] ids) {
        return toAjax(adjustOutBillService.deleteAdjustOutBillByIds(ids));
    }

    /**
     * 订单完成
     */
    @ApiOperation(value = "订单完成")
    @Log(title = "订单完成", businessType = BusinessType.UPDATE)
    @PutMapping("/complete")
    public AjaxResult complete(@RequestBody List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            throw new ServiceException("缺少必要参数");
        }

        return toAjax(adjustOutBillService.complete(ids));
    }

    /**
     * 订单确认
     */
    @ApiOperation(value = "订单确认")
    @Log(title = "订单确认", businessType = BusinessType.UPDATE)
    @PutMapping("/confirm")
    public AjaxResult confirm(@RequestBody List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            throw new ServiceException("缺少必要参数");
        }
        int result=adjustOutBillService.confirm(ids);
        return toAjax(result);
    }


    /**
     * 调拔出库导入模板
     */
    @ApiOperation(value = "调拔出库导入模板")
    @PostMapping("/importTemplate")
    public void importTemplate(HttpServletResponse response) {
        ExcelUtil<AdjustOutBillExportVo> util = new ExcelUtil<>(AdjustOutBillExportVo.class);
        util.importTemplateExcel(response, "调拔出库导入模板");
    }

    /**
     * 导入调拔入库
     */
    @ApiOperation(value = "导入调拔入库")
    @PostMapping("/importExcel")
    @Log(title = "导入调拔入库", businessType = BusinessType.IMPORT)
    public AjaxResult importExcel(MultipartFile file) {
        List<AdjustOutBillExportVo> list;
        try {
            //读取excel文件数据
            ExcelUtil<AdjustOutBillExportVo> util = new ExcelUtil<>(AdjustOutBillExportVo.class);
            list = util.importExcel(file.getInputStream());
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException("导入文件解析失败");
        }
        //初步校验数据
        if (CollectionUtils.isEmpty(list)) {
            throw new ServiceException("文件缺少数据");
        }

        //深入校验数据和保存数据
        List<String> errorList = adjustOutBillService.importExcel(list);
        if (!errorList.isEmpty()) {
            StringBuilder failureMsg = new StringBuilder();
            failureMsg.append("很抱歉，导入失败！共 ").append(errorList.size()).append(" 条数据格式不正确，错误如下：");
            for (int i = 0; i < errorList.size(); i++) {
                failureMsg.append("<br/>").append(i + 1).append("、").append(errorList.get(i));
            }
            return error(failureMsg.toString());
        }
        return success("导入成功");
    }


    /**
     * 订单取消
     */
    @ApiOperation(value = "订单取消")
    @Log(title = "订单取消", businessType = BusinessType.UPDATE)
    @PutMapping("/cancel")
    public AjaxResult cancel(@RequestBody List<Long> ids) {
        return success(adjustOutBillService.cancel(ids));
    }

    /**
     * 订单确认取消
     */
    @ApiOperation(value = "订单确认取消")
    @Log(title = "订单取消", businessType = BusinessType.UPDATE)
    @PutMapping("/confirmCancel")
    public AjaxResult cancel(@RequestBody AdjustOutBill adjustOutBill) {
        if(adjustOutBill == null || adjustOutBill.getId() == null){
            throw new ServiceException("缺少必要参数");
        }
        return success(adjustOutBillService.confirmCancel(adjustOutBill));
    }

    @ApiOperation(value = "调拨出库执行")
    @Log(title = "调拨出库执行", businessType = BusinessType.UPDATE)
    @PostMapping("/execute")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult execute(@RequestBody List<AdjustOutBill> adjustOutBills) {
        if(adjustOutBills==null||adjustOutBills.size()==0){
            return error("调拨出库单数据为空");
        }
        for (AdjustOutBill item :adjustOutBills){
            AdjustOutBill data=adjustOutBillService.selectAdjustOutBillByNo(item.getNo());
            if(data==null){
                return error("调拨出库单"+item.getNo()+"数据不存在");
            }
            if(OutOrderStatusEnum.NEW.getCode().equals(data.getStatus())) {
                adjustOutBillDispatcher(data);
            }
            else if(OutOrderStatusEnum.WAITING_PICK.getCode().equals(data.getStatus())){
                prePickOutBillDispatcher(data);
            }
        }
        return toAjax(1);
    }

    /**
     * 调拨出库单分配
     * @param adjustOutBill 调拨出库单
     */
    public void adjustOutBillDispatcher(AdjustOutBill adjustOutBill){
        logger.info("开始出库：{}", adjustOutBill.toString());
        //查询调拨出库单明细
        List<String> productNos=new ArrayList<>();
        List<Long> productCounts=new ArrayList<>();
        String stockStatus=adjustOutBill.getStockStatus();
        AdjustOutBillDetail query=new AdjustOutBillDetail();
        query.setBillNo(adjustOutBill.getNo());
        query.setDelFlag("0");
        List<AdjustOutBillDetail> details=adjustOutBillDetailService.selectAdjustOutBillDetailList(query);
        for (AdjustOutBillDetail detail :details){
            productNos.add(detail.getProductNo());
            productCounts.add(detail.getQty());
        }
        //OutStockQueryVo赋值
        OutStockQueryVo outStockQueryVo=new OutStockQueryVo();
        outStockQueryVo.setStockStatus(stockStatus);
        outStockQueryVo.setProductNos(productNos);
        outStockQueryVo.setProductCounts(productCounts);
        outStockQueryVo.setBillNo(adjustOutBill.getNo());
        outStockQueryVo.setBillType(ErpBillTypeEnum.ADJUST_OUT.getCode());
        outStockQueryVo.setCellCode(adjustOutBill.getAddress());
        outStockQueryVo.setShortMatch(adjustOutBill.getShortMatch());

        OutStockResultVo outStockResultVo= adjustOutBillService.analyseOutStock(outStockQueryVo);

        for (AdjustOutBillDetail item:details) {
            List<OutStockBillDetail> outStockBillDetails =outStockResultVo.getOutStockBillDetails().stream().filter(O->O.getProductNo().equals(item.getProductNo())).collect(Collectors.toList());
            if(outStockBillDetails.size()!=0){
                OutStockBillDetail outStockBillDetail=outStockBillDetails.get(0);
                item.setBatchNo(outStockBillDetail.getBatchNo());
            }
        }
        adjustOutBillDetailService.batchUpdateAdjustOutBillDetail(details);
        adjustOutBill.setStatus(OutOrderStatusEnum.PICKING.getCode());
        adjustOutBillService.updateAdjustOutBill(adjustOutBill);
        logger.info("出库分配成功：{}", details.toString());
        adjustOutBillService.postOutStockCallback(adjustOutBill.getNo(),adjustOutBill.getStockStatus());
        logger.info("出库成功：{}", adjustOutBill.toString());
    }

    /**
     * 预选出库单分配
     */
    public void prePickOutBillDispatcher(AdjustOutBill adjustOutBill){
        AdjustOutBillDetail query=new AdjustOutBillDetail();
        query.setBillNo(adjustOutBill.getNo());
        query.setDelFlag("0");
        List<AdjustOutBillDetail> details=adjustOutBillDetailService.selectAdjustOutBillDetailList(query);
        OutStockResultVo outStockResultVo= adjustOutBillService.handlePreOutStockBill(adjustOutBill.getNo(),ErpBillTypeEnum.ADJUST_OUT.getCode(),adjustOutBill.getAddress());
        for (AdjustOutBillDetail item:details) {
            List<OutStockBillDetail> outStockBillDetails =outStockResultVo.getOutStockBillDetails().stream().filter(O->O.getProductNo().equals(item.getProductNo())).collect(Collectors.toList());
            if(outStockBillDetails.size()!=0){
                OutStockBillDetail outStockBillDetail=outStockBillDetails.get(0);
                item.setBatchNo(outStockBillDetail.getBatchNo());
            }
        }
        adjustOutBillDetailService.batchUpdateAdjustOutBillDetail(details);
        adjustOutBill.setStatus(OutOrderStatusEnum.PICKING.getCode());
        adjustOutBillService.updateAdjustOutBill(adjustOutBill);
        adjustOutBillService.postOutStockCallback(adjustOutBill.getNo(),adjustOutBill.getStockStatus());
        logger.info("出库成功：{}", adjustOutBill);
    }


    /**
     * 调拨出库单打印
     */
    @ApiOperation(value = "调拨出库单打印")
    @Log(title = "调拨出库单打印", businessType = BusinessType.EXPORT)
    @GetMapping("/selectAdjustOutBillForPrint")
    public AjaxResult selectAdjustOutBillForPrint(@RequestParam("no") String no) {
        return success(adjustOutBillService.selectAdjustOutBillForPrint(no));
    }
}
